package VocSymbTest2;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeSet;

public class CanonicalSets<K extends ItemSet> extends ItemSetFamily{
	/*ArrayList<ItemSet> canonicalSets;
    ArrayList<ItemSet> canonicalSetsMinusNonkernalItems;
    ArrayList<ItemSet> canonicalSetsGotoReduced;
    //ArrayList<ArrayList<VocabularySymbol>> Action;
    //ArrayList<ArrayList<VocabularySymbol>> Goto;    // later implementation for dynamic language input
                                                    // goto ArrayList will have dynamic size 
    String[][] Action = new String[17][17];
    String[][] Goto = new String[17][17];
    
    
    //  default constructor
    public ItemSetFamily(){
        canonicalSets = new ArrayList<>();
        canonicalSetsMinusNonkernalItems = new ArrayList<>();
        canonicalSetsGotoReduced = new ArrayList<>();
        for(int i = 0 ; i < Action.length; i++){
            for(int j = 0; j < Action[i].length; j++){
                Action[i][j] = new String("");
            }
        }
        for(int i = 0 ; i < Goto.length; i++){
            for(int j = 0; j < Goto[i].length; j++){
                Goto[i][j] = new String("");
            }
        }
        itemSetFamily = new TreeSet<>(new ItemSetComparator());
    }
    
    //  constructor
    public ItemSetFamily(ItemSet itemSet){
        for(int i = 0 ; i < Action.length; i++){
            for(int j = 0; j < Action[i].length; j++){
                Action[i][j] = new String("");
            }
        }
        for(int i = 0 ; i < Goto.length; i++){
            for(int j = 0; j < Goto[i].length; j++){
                Goto[i][j] = new String("");
            }
        }
        //Action = new ArrayList<>();
        //Goto = new ArrayList<ArrayList<VocabularySymbol>>();
        //((ArrayList)Goto).ensureCapacity(16);
        //while(Goto.size() < 16){
        //    Goto.add(null);
        //}
        //for(int i = 0; i < 16; i++){
            //((ArrayList)Goto).ensureCapacity(16);
            //((ArrayList)Goto.get(i)).add(new ArrayList<VocabularySymbol>(16));
            //ArrayList<VocabularySymbol> vocabArrayList = new ArrayList<>();
            //((ArrayList)vocabArrayList).ensureCapacity(16);
            //((ArrayList)Goto.get(i)).add(vocabArrayList);
            //while(((ArrayList)Goto.get(i)).size() < 16){
            //    ((ArrayList)Goto.get(i)).add(null);
            //}
            //((ArrayList)Goto.get(i)).add(new ArrayList<VocabularySymbol>());
            //((ArrayList)Goto.get(i)).ensureCapacity(16);
        //}
        canonicalSets = new ArrayList<>();
        canonicalSetsMinusNonkernalItems = new ArrayList<>();
        canonicalSetsGotoReduced = new ArrayList<>();
        itemSetFamily = new TreeSet<>(new ItemSetComparator());
        itemSetFamily.add(itemSet);
        canonicalSets.add(itemSet);
    }
    
    //  copy constructor
    public ItemSetFamily(ItemSetFamily itemSetFamilyToCopy){
        for(int i = 0 ; i < Action.length; i++){
            for(int j = 0; j < Action[i].length; j++){
                Action[i][j] = new String("");
            }
        }
        for(int i = 0 ; i < Goto.length; i++){
            for(int j = 0; j < Goto[i].length; j++){
                Goto[i][j] = new String("");
            }
        }
        //Action = new ArrayList<>();
        //Goto = new ArrayList<ArrayList<VocabularySymbol>>();
        //((ArrayList)Goto).ensureCapacity(16);
        //while(Goto.size() < 16){
        //    Goto.add(null);
        //}
        //for(int i = 0; i < 16; i++){
         	//((ArrayList)Goto).ensureCapacity(16);
            //((ArrayList)Goto.get(i)).add(new ArrayList<VocabularySymbol>(16));
            //ArrayList<VocabularySymbol> vocabArrayList = new ArrayList<>();
            //((ArrayList)vocabArrayList).ensureCapacity(16);
            //((ArrayList)Goto.get(i)).add(vocabArrayList);
            //while(((ArrayList)Goto.get(i)).size() < 16){
            //    ((ArrayList)Goto.get(i)).add(null);
            //}
            //((ArrayList)Goto.get(i)).add(new ArrayList<VocabularySymbol>());
            //((ArrayList)Goto.get(i)).ensureCapacity(16);
        //}
        canonicalSets = new ArrayList<>();
        canonicalSetsMinusNonkernalItems = new ArrayList<>();
        canonicalSetsGotoReduced = new ArrayList<>();
        itemSetFamily = new TreeSet<>(new ItemSetComparator());
        
        for(ItemSet itemSet : itemSetFamilyToCopy.canonicalSets){
            canonicalSets.add(itemSet);
        }
        for(ItemSet itemSet : itemSetFamilyToCopy.canonicalSetsMinusNonkernalItems){
            canonicalSetsMinusNonkernalItems.add(itemSet);
        }
        for(ItemSet itemSet : itemSetFamilyToCopy.canonicalSetsGotoReduced){
            canonicalSetsGotoReduced.add(itemSet);
        }
        
        for(ItemSet itemSet : itemSetFamilyToCopy.itemSetFamily){
            itemSetFamily.add(itemSet);
        }
        
        for(int targetState = 0; targetState < Action.length; targetState++){
            for (int itr = 0; itr < Action[targetState].length; itr++){
                Action[targetState][itr] = itemSetFamilyToCopy.Action[targetState][itr];
            }
        }
        for(int targetState = 0; targetState < itemSetFamilyToCopy.Goto.length; targetState++){
            for (int itr = 0; itr < itemSetFamilyToCopy.Goto[targetState].length; itr++){
                Goto[targetState][itr] = itemSetFamilyToCopy.Goto[targetState][itr];
            }
        }
        
        //for(int targetState = 0; targetState < Action.size(); targetState++){
        //    for (int itr = 0; itr < ((ArrayList)Action.get(targetState)).size(); itr++){
        //        ((VocabularySymbol)((ArrayList)Action.get(targetState)).get(itr)).symbol = ((VocabularySymbol)((ArrayList)((itemSetFamilyToCopy.Action).get(targetState))).get(itr)).GetSymbolChar();
        //    }
        //}
        //for(int targetState = 0; targetState < Goto.size(); targetState++){
        //    for (int itr = 0; itr < ((ArrayList)Goto.get(targetState)).size(); itr++){
        //        ((VocabularySymbol)((ArrayList)Goto.get(targetState)).get(itr)).symbol = ((VocabularySymbol)((ArrayList)((itemSetFamilyToCopy.Goto).get(targetState))).get(itr)).GetSymbolChar();
        //    }
        //}
    }
    
    public ItemSetFamily ConstructCanonicalSetsNonKernal(ItemSetFamily toGetRidOfNonKernal){
        ItemSet tempItemSet = new ItemSet();
        ItemSetFamily itemSetFamilyNoNonKernal = new ItemSetFamily();
        for(ItemSet itemSet : toGetRidOfNonKernal.itemSetFamily){
            tempItemSet = new ItemSet();
            for(Item item : itemSet.itemSet){
                if(item.GetSource().symbol == 'S' || !item.stringBeforeDot.grammarString.isEmpty()){
                    tempItemSet.itemSet.add(item);
                }
            }
            itemSetFamilyNoNonKernal.itemSetFamily.add(tempItemSet);
        }
        return itemSetFamilyNoNonKernal;
    }
    
    public void ConstructCanonicalSetSetsGotoReduced(Grammar grammar){
        boolean addItemSet = true;
        for (int it1 = 0; it1 < canonicalSets.size(); it1++) {
            addItemSet = true;
            for (int it2 = 0; it2 < canonicalSets.size(); it2++) {
                //System.out.println("Check if the set X: ");
                //canonicalSets.get(it1).Print();
                //System.out.println();
                //System.out.println("will goto reduce to the set Y: ");
                //canonicalSets.get(it2).Print();
                //System.out.println();
                Iterator nonTermIter = grammar.allNonTerminals.vocabularySymbolSet.iterator();
                nonTermIter.next();
                Iterator termIter = grammar.allTerminals.vocabularySymbolSet.iterator();
                for (int allNonTerminalsItr = 1; nonTermIter.hasNext() && allNonTerminalsItr < grammar.allNonTerminals.vocabularySymbolSet.size(); allNonTerminalsItr++) {
                    
                    NonTerminal nonTerminal = (NonTerminal) nonTermIter.next();
                    if(canonicalSets.get(it1).GotoReduce(nonTerminal, canonicalSets.get(it2), grammar)){
                        addItemSet = false;
                        Goto[it1][it2] = Character.toString(nonTerminal.symbol);
                    }
                    
                }
                for (int allTerminalsSize = 0; termIter.hasNext() && allTerminalsSize < grammar.allTerminals.vocabularySymbolSet.size(); allTerminalsSize++) {
                    
                    Terminal terminal = (Terminal) termIter.next();
                    if(canonicalSets.get(it1).GotoReduce(terminal, canonicalSets.get(it2), grammar)){
                        addItemSet = false;
                        Goto[it1][it2] = Character.toString(terminal.symbol);
                    }
                }
            }
            
            if(addItemSet){
                //System.out.println("It does goto reduce****************************************");
                
            }
            else {
                //System.out.println("X does not goto reduce to Y.");
                //System.out.println();
                canonicalSetsGotoReduced.add(canonicalSets.get(it1));
            }
        }
    }
    
    public ItemSet GOTO(ItemSet canSet, VocabularySymbol vocSymb, Grammar grammar){
        ItemSet canSetToReturn = new ItemSet();
        int indexOfCanSetToReturn = -1;
        if(canonicalSets.contains(canSet)){
            for(int i = 0; i < Goto.length; i++){
                if(Goto[canonicalSets.indexOf(canSet)][i].equals(Character.toString(vocSymb.GetSymbolChar()))){
                    indexOfCanSetToReturn = i;
                }
            }
        }
        if(indexOfCanSetToReturn == -1){
            canSetToReturn = new ItemSet();
        }else{
            canSetToReturn = new ItemSet(canonicalSets.get(indexOfCanSetToReturn));
        }
        
        return canSetToReturn;
    }
    
    public String Action(int i, VocabularySymbol vocSymb, Grammar grammar){
        boolean foundStart = false;
        int count = 0;
        int gotoCanSetIndex = 0;
        char terminalCharAfterDot;
        String returnString = "";
        ItemSet stateSet = new ItemSet();
        ItemSet gotoSet = new ItemSet();
        if(i>=0 && i < canonicalSets.size()){
            stateSet = canonicalSets.get(i);
                gotoSet = GOTO(stateSet,vocSymb, grammar);
                if(!gotoSet.itemSet.isEmpty()){
                    for(ItemSet findItemSet : canonicalSets){

                        if(gotoSet.compareTo(findItemSet) == 0){
                            gotoCanSetIndex = count;
                        }else{
                            count++;
                        }
                    }
                    returnString = "s" + String.valueOf(gotoCanSetIndex);
                    count = 0;
                }
                if(vocSymb.symbol != 'S'){
                    for(Item item : stateSet.itemSet){
                        if(item.stringAfterDot.grammarString.isEmpty()){
                            VocabularySymbol head = new NonTerminal(item.source);
                            for(VocabularySymbol followOfHead: grammar.allNonTerminals.vocabularySymbolSet){
                                if(followOfHead.symbol == head.symbol){
                                    for(VocabularySymbol followSym: followOfHead.GetFollow().vocabularySymbolSet){
                                        if(vocSymb.symbol == followSym.symbol){
                                            for(GrammarRule gramRule : grammar.allGrammarRules.grammarRuleList){
                                                if(gramRule.source.symbol == head.symbol){
                                                    if(gramRule.target.compareTo(item.stringBeforeDot) == 0){
                                                        returnString = "r" + String.valueOf(grammar.allGrammarRules.GetGrammarRuleIndex(gramRule));
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                for(Item startItem : stateSet.itemSet){
                    foundStart = startItem.source.symbol == 'S' 
                                && !startItem.stringBeforeDot.grammarString.isEmpty()
                                && startItem.stringBeforeDot.grammarString.get(0).symbol == 'E'
                                && startItem.stringAfterDot.grammarString.isEmpty();
                    if(foundStart){
                        if(vocSymb.symbol == '$'){
                            returnString = "accept";
                        }
                    }
                }
            }
        return returnString;
    }
    
    public void PrintItemSetFamily(){
        for (Iterator<ItemSet> it = itemSetFamily.iterator(); it.hasNext();) {
            ItemSet itemSet = it.next();
            System.out.print('{');
            itemSet.Print();
            System.out.print('}');
        }
    }
    
    public void PrintGotoTable(Grammar grammar){
        int intToPrint = -1;
        System.out.println("The Goto table is:");
        System.out.printf("%-3s"," ");
        for(VocabularySymbol vocSymb: grammar.allNonTerminals.vocabularySymbolSet){
                System.out.printf("%-3s",vocSymb.symbol);
        }
        System.out.println();
        for(int i = 0; i < canonicalSets.size(); i++){
            System.out.printf("%-3s",i);
            for(VocabularySymbol vocSymb: grammar.allNonTerminals.vocabularySymbolSet){
                intToPrint = Goto(i, vocSymb, grammar);
                if(intToPrint >= 0 && intToPrint <= canonicalSets.size()){
                    System.out.printf("%-3s",intToPrint);
                }
                else{
                    System.out.printf("%-3s"," ");
                }
                
            }
            System.out.println();
        }
    }
    
    public void PrintCanonicalSets(){
        int count = 0;
        System.out.println("The canonical sets are: ");
        for (Iterator<ItemSet> it = canonicalSets.iterator(); it.hasNext();) {
            ItemSet itemSet = it.next();
            System.out.print("I");
            System.out.print(count);
            System.out.print(" = {");
            itemSet.Print();
            System.out.println('}');
            count++;
        }
    }
    
    public void PrintCanonicalSetsNonKernal(ItemSetFamily toPrintFamily){
        int count = 0;
        System.out.println("The canonical sets without nonkernal items are: ");
        for (Iterator<ItemSet> it = toPrintFamily.itemSetFamily.iterator(); it.hasNext();) {
            ItemSet itemSet = it.next();
            System.out.print("I");
            System.out.print(count);
            System.out.print(" = {");
            itemSet.Print();
            System.out.println('}');
            count++;
        }
    }
    
    public void PrintCanonicalSetsGotoReduced(){
        int count = 0;
        System.out.println("The canonical sets goto reduced are: ");
        for (Iterator<ItemSet> it = canonicalSetsGotoReduced.iterator(); it.hasNext();) {
            ItemSet itemSet = it.next();
            System.out.print("I");
            System.out.print(count);
            System.out.print(" = {");
            itemSet.Print();
            System.out.println('}');
            count++;
        }
        System.out.println();
    }
    
    public void PrintTransitionTable(){
        System.out.println("The transition Table is:");
        System.out.print("   ");
        for(int i = 0; i < Goto.length; i++){
            System.out.printf("%-3s",i);
        }
        System.out.println();
        for(int i = 0; i < Goto.length; i++){ 
            System.out.printf("%-3s",i);
            for(int j = 0; j < Goto[i].length; j++){
                System.out.printf("%-3s",Goto[i][j]);
            }
            System.out.println();
        }
    }
    
    void PrintActionTable(Grammar grammar){
        System.out.println("The Action Table is");
        System.out.printf("%-10s", " ");
        for(VocabularySymbol vocSymb: grammar.allTerminals.vocabularySymbolSet){
            if(vocSymb.symbol != 'e'){
                System.out.printf("%-10s",vocSymb.symbol);
            }
        }
        System.out.println();
        
        System.out.print("-------------------------------------------------");
        System.out.println("------------------------------------------------");
        for(int i = 0; i < canonicalSets.size(); i++){
            System.out.printf("%-10s", i);
            for(VocabularySymbol vocSymb : grammar.allTerminals.vocabularySymbolSet){
                if(vocSymb.symbol != 'e'){
                    System.out.printf("%-10s",Action(i, vocSymb, grammar));
                }
            }
            System.out.println();
        }
    }
    
    public int Goto(int canSetIndex, VocabularySymbol nonTerminal, Grammar grammar){
        int indexOfCanSetToReturn = -1;
        int count = 0;
        ItemSet canSetToReturn = new ItemSet();
        if(0<=canSetIndex && canSetIndex < canonicalSets.size()){
            canSetToReturn = canonicalSets.get(canSetIndex);
        }
        for (ItemSet itemSet : canonicalSets){
            if( itemSet.compareTo(GOTO(canSetToReturn, nonTerminal, grammar)) == 0){
                indexOfCanSetToReturn = count;
                
            }
            count++;
        }
        return indexOfCanSetToReturn;
    }*/
}